//
//  RxSwiftViewController.swift
//  test-ios
//
//  Created by wyz5204 on 2023/3/1.
//

import UIKit
import RxSwift
import RxCocoa
import RxDataSources
import RxAlamofire
import Moya

import ObjectMapper
import SwiftyJSON
import CocoaLumberjack

/**
 简单的rxswift的使用和开发
 */
class RxSwiftViewController: UIViewController{
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let flowLayout = UICollectionViewFlowLayout()
        flowLayout.itemSize = CGSize(width: self.view.width, height: 30)
        
        flowLayout.headerReferenceSize = CGSize(width: self.view.frame.width, height: 40)
        
        let collect = UICollectionView(frame: self.view.frame,collectionViewLayout: flowLayout)
        
        collect.backgroundColor = UIColor.white
        collect.register(RxSwiftCell.self, forCellWithReuseIdentifier: "Cell")
        collect.register(RxSwiftHeader.self,  forSupplementaryViewOfKind:UICollectionView.elementKindSectionHeader, withReuseIdentifier: "Header")
        self.view.addSubview(collect)
        
        // 创建数据源
        let sections = Observable.just(data)
        // 绑定数据源
        let dataSource = RxCollectionViewSectionedReloadDataSource<MySection>(
            configureCell: { (dataSource, collectionView, indexPath, element) in
                let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell",
                                                              for: indexPath) as! RxSwiftCell
                cell.initBinder(collectionView , element ,indexPath )
                return cell} ,
            
            configureSupplementaryView: {
                (ds ,cv, kind, ip) in
                let section = cv.dequeueReusableSupplementaryView(ofKind: kind,
                                                                  withReuseIdentifier: "Header", for: ip) as! RxSwiftHeader
                section.binder(ds[ip.section].header)
                return section
            }
            
        )
        
        sections.bind(to: collect.rx.items(dataSource: dataSource))
            .disposed(by: rx.disposeBag)
        collect.scrollToItem(at: IndexPath.init(row: 10, section: 0), at: .top, animated: true)
        
        collect.rx.itemSelected.asDriver().drive(onNext: { [weak self] element  in
            
            guard  let this = self else {
                return
            }
            print(element ,element.section ,element.row , this.data[element.section].items[element.row])
            
            if(this.data[element.section].items[element.row] == "observable_of"){
                this.observable_of()
                return ;
            }
            if(this.data[element.section].items[element.row] == "observable_just"){
                this.observable_just()
                return ;
            }
            if(this.data[element.section].items[element.row] == "observable_from"){
                this.observable_from()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "observable_bind"){
                this.observable_bind()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "observable_empty"){
                this.observable_empty()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "observable_never"){
                this.observable_never()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "observable_error"){
                this.observable_error()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "observable_range"){
                this.observable_range()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "observable_repeatElement"){
                this.observable_repeatElement()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "observable_generate"){
                this.observable_generate()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "observable_deferred"){
                this.observable_deferred()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "observable_interval"){
                this.observable_interval()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "observable_timer"){
                this.observable_timer()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "observable_do"){
                this.observable_do()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_AnyObserverAndBinder"){
                this.use_AnyObserverAndBinder()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "observable_observe_subscribe"){
                this.observable_observe_subscribe()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_request"){
                this.use_request()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_request_data"){
                this.use_request_data()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_request_json"){
                this.use_request_json()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_request_json_to_bean"){
                this.use_request_json_to_bean()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_moya_request"){
                this.use_moya_request()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_moya_request_json"){
                this.use_moya_request_json()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_moya_request_demo"){
                this.use_moya_request_demo(title: "title", message: "message")
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_PublishSubject"){
                this.use_PublishSubject()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_BehaviorSubject"){
                this.use_BehaviorSubject()
                return ;
            }
            
            
            if(this.data[element.section].items[element.row] == "use_ReplaySubject"){
                this.use_ReplaySubject()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_BehaviorRelay"){
                this.use_BehaviorRelay()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_startWith"){
                this.use_startWith()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_merge"){
                this.use_merge()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_zip"){
                this.use_zip()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_combineLatest"){
                this.use_combineLatest()
                return ;
            }
            
            if(this.data[element.section].items[element.row] == "use_withLatestFrom"){
                this.use_withLatestFrom()
                return ;
            }
        }).disposed(by: rx.disposeBag)
        
    }
    
    let data = [
        MySection(header: "RxSwift 基础", items: [
            "observable_of",
            "observable_just",
            "observable_from",
            "observable_bind",
            "observable_empty",
            "observable_never",
            "observable_error",
            "observable_range",
            "observable_repeatElement",
            "observable_generate",
            "observable_create",
            "observable_deferred",
            "observable_interval",
            "observable_timer",
            "observable_do",
            "use_AnyObserverAndBinder",
            "observable_observe_subscribe"
        ]),
        MySection(header: "Subjects", items: [
            "use_PublishSubject",
            "use_BehaviorSubject",
            "use_ReplaySubject",
            "use_BehaviorRelay"
        ]),
        MySection(header: "变换操作符", items: [
            "use_buffer",
            "use_window",
            "use_map",
            "use_flatMap",
            "use_flatMapLatest",
            "use_concatMap",
            "use_scan",
            "use_groupBy"
        ]),
        MySection(header: "过滤操作符", items: [
            "use_filter",
            "use_distinctUntilChanged",
            "use_single",
            "use_elementAt",
            "use_ignoreElements",
            "use_take",
            "use_takeLast",
            "use_skip",
            "use_sample",
            "use_debounce"
        ]),
        MySection(header: "条件和布尔操作符", items: [
            "use_amb",
            "use_takeWhile",
            "use_takeUntil",
            "use_skipWhile",
            "use_skipUntil"
        ]),
        MySection(header: "结合操作符", items: [
            "use_startWith",
            "use_merge",
            "use_zip",
            "use_combineLatest",
            "use_withLatestFrom",
            "use_switchLatest"
        ]),
        MySection(header: "算数&聚合操作符", items: [
            "use_toArray",
            "use_reduce",
            "use_concat"
        ]),
        MySection(header: "连接操作符", items: [
            "use_publish",
            "use_replay",
            "use_multicast",
            "use_refCount",
            "use_share"
        ]),
        MySection(header: "其他操作符", items: [
            "use_delay",
            "use_delaySubscription",
            "use_materialize",
            "use_dematerialize",
            "use_timeout",
            "use_using"
        ]),
        MySection(header: "错误处理", items: [
            "use_catchErrorJustReturn",
            "use_catchError",
            "use_retry"
        ]),
        MySection(header: "调试操作", items: [
            "use_debug",
            "use_delaySubscription",
            "use_materialize",
            "use_dematerialize",
            "use_timeout",
            "use_using"
        ]),
        MySection(header: "RxSwift 网络 RxAlamofire", items: [
            "use_request",
            "use_request_data",
            "use_request_json",
            "use_request_json_to_bean"
        ]),
        MySection(header: "RxSwift 网络 RxMoya", items: [
            "use_moya_request",
            "use_moya_request_json",
            "use_moya_request_demo"
        ])
    ]
    
    //该方法可以接受可变数量的参数（必需要是同类型的）
    func observable_of(){
        Observable.of("aaa0","aaa1","aaa2","aaa3").subscribe { element in
            print("observable_of onNext" , element , Thread.current)
        } onError: { error in
            print("observable_of onError" , error, Thread.current)
        } onCompleted: {
            print("observable_of onCompleted", Thread.current)
        } onDisposed: {
            print("observable_of onDisposed", Thread.current)
        }.disposed(by: rx.disposeBag)
    }
    
    
    //该方法通过传入一个默认值来初始化
    func observable_just(){
        Observable.just("aaa").subscribe { element in
            print("observable_just onNext" , element , Thread.current)
        } onError: { error in
            print("observable_just onError" , error, Thread.current)
        } onCompleted: {
            print("observable_just onCompleted", Thread.current)
        } onDisposed: {
            print("observable_just onDisposed", Thread.current)
            
        }.disposed(by: rx.disposeBag)
    }
    
    
    //该方法通过传入一个默认值来初始化
    func observable_from(){
        Observable.from(["aaa1","aaa2","aaa3","aaa4"]).subscribe { element in
            print("observable_from onNext" , element , Thread.current)
        } onError: { error in
            print("observable_from onError" , error, Thread.current)
        } onCompleted: {
            print("observable_from onCompleted", Thread.current)
        } onDisposed: {
            print("observable_from onDisposed", Thread.current)
            
            DDLogVerbose("Verbose")
            DDLogDebug("Debug")
            DDLogInfo("Info")
            DDLogWarn("Warn")
            DDLogError("Error")
            
        }.disposed(by: rx.disposeBag)
    }
    
    // 该PublishSubject 能够使得即便是发送oncomplse事件后的再注册也能收到 结束事件，
    // 用来发送，必须要让观察者知道的，是否完成或者失败的情况，使用publishSubject
    func use_PublishSubject(){
        let publish = PublishSubject<String>()
        
        publish.onNext(">>>>>>>>>>>>>>> 1")
        publish.subscribe { event in
            DDLogDebug(" observer1 \(event)")
        }.disposed(by: rx.disposeBag)
        
        publish.onNext(">>>>>>>>>>>>>>> 2")
        publish.subscribe { value in
            DDLogDebug("onNext2 \(value)")
        } onError: { error in
            DDLogDebug("onError2 \(error)")
        } onCompleted: {
            DDLogDebug("onCompleted2 ")
        } onDisposed: {
            DDLogDebug("onDisposed2 ")
        }.disposed(by: rx.disposeBag)
        
        publish.onNext(">>>>>>>>>>>>>>> 3")
        //让subject结束
        publish.onCompleted()
        publish.onNext(">>>>>>>>>>>>>>> 4 ")
        
        publish.subscribe { event in
            DDLogDebug(" observer3 \(event)")
        }.disposed(by: rx.disposeBag)
        
    }
    //PublishSubject 相同的功能，但有个初始值，可以直接赋予初始化，订阅者订阅就能够收到事件
    func use_BehaviorSubject(){
        let subject = BehaviorSubject.init(value: "1111")
        subject.subscribe { event in
            DDLogDebug(" subscribe 1 >> \(event)")
        }.disposed(by: rx.disposeBag)
        subject.onNext("2222")
        subject.onCompleted()
        subject.subscribe { event in
            DDLogDebug(" subscribe 2 >> \(event)")
        }.disposed(by: rx.disposeBag)
        
    }
    
    //该ReplaySubject是个能够缓存的，支持设置
    func use_ReplaySubject(){
        let replay = ReplaySubject<String>.create(bufferSize: 2)
        replay.onNext("1")
        replay.onNext("2")
        replay.onNext("3")
        replay.subscribe { event in
            DDLogDebug(" observer[1] \(event)")
        }.disposed(by: rx.disposeBag)
        
        replay.onNext("4")
        replay.subscribe { event in
            DDLogDebug(" observer[2] \(event)")
        }.disposed(by: rx.disposeBag)
        
        //让subject结束
        replay.onCompleted()
        replay.subscribe { event in
            DDLogDebug(" observer[3] \(event)")
        }.disposed(by: rx.disposeBag)
        
    }
    // BehaviorRelay 就是 BehaviorSubject 去掉终止事件 onError 或 onCompleted。
    func use_BehaviorRelay(){
        let br =  BehaviorRelay.init(value: "11")
        br.subscribe { DDLogDebug("Event 1: \($0)") }
            .disposed(by: rx.disposeBag)
        br.accept("22")
        br.accept("33")
        br.subscribe { DDLogDebug("Event 2: \($0)") }
            .disposed(by: rx.disposeBag)
        br.accept("44")
    }
    
    ///------------------------------------结合操作符
    func use_startWith(){
        Observable.of("1" , "2" , "3")
            .startWith("-3")
            .startWith("-2")
            .startWith("-1")
            .startWith("0")
            .subscribe { event in
                DDLogDebug(event)
            }.disposed(by: rx.disposeBag)
    }
    
    func use_merge(){
        let publish1 = PublishSubject<String>()
        let publish2 = PublishSubject<String>()
        Observable.of(publish1 , publish2)
            .merge()
            .subscribe { event in
                DDLogDebug(event)
            }.disposed(by: rx.disposeBag)
        
        publish1.onNext("publish1 1")
        publish2.onNext("publish2 2")
        publish1.onNext("publish1 1")
        publish2.onNext("publish2 3")
        publish1.onNext("publish1 1")
        publish2.onNext("publish2 4")
    }
    
    func use_zip(){
        
        let publish1 = PublishSubject<Int>()
        let publish2 = PublishSubject<String>()
        let publish3 = PublishSubject<Bool>()
        
        Observable.zip(publish1 ,publish2 ,publish3  , resultSelector : {a,b,c -> String in
            return "\(a) >> \(b) >> \(c)"
        }).subscribe { event in
            DDLogDebug(event)
        }.disposed(by: rx.disposeBag)
        
        publish1.onNext(1)
        publish1.onNext(2)
        publish2.onNext("3")
        publish3.onNext(true)
        publish2.onNext("4")
        publish3.onNext(false)
        
    }
    
    func use_combineLatest(){
        let publish1 = PublishSubject<Int>()
        let publish2 = PublishSubject<String>()
        let publish3 = PublishSubject<Bool>()
        
        Observable.combineLatest(publish1 ,publish2 ,publish3  , resultSelector : {a,b,c -> String in
            return "\(a) >> \(b) >> \(c)"
        }).subscribe { event in
            DDLogDebug(event)
        }.disposed(by: rx.disposeBag)
        
        publish1.onNext(1)
        publish1.onNext(2)
        publish2.onNext("3")
        publish3.onNext(true)
        publish2.onNext("4")
        publish3.onNext(false)
    }
    
    func use_withLatestFrom(){
        let send = PublishSubject<Int>()
        let switchButton = PublishSubject<String>()
        switchButton.withLatestFrom(send)
            .subscribe { event in
                DDLogDebug(event)
            }.disposed(by: rx.disposeBag)
        
        switchButton.onNext("1")
        send.onNext(2)
        
        switchButton.onNext("1")
        send.onNext(3)
        send.onNext(4)
        
        switchButton.onNext("1")
        switchButton.onNext("1")
        send.onNext(5)
        send.onNext(6)
        switchButton.onNext("1")
    }
    ///------------------------------------
    
    /**
     该方法通过传入一个默认值来初始化
     */
    func observable_bind(){
        Observable.from(["aaa1","aaa2","aaa3","aaa4"])
            .bind { text in
                print("observable_bind onNext",text ,  Thread.current)
            }.disposed(by: rx.disposeBag)
    }
    
    // 只会发送 completed 事件
    func observable_empty(){
        Observable<Int>.empty().subscribe { event in
            print("observable_empty subscribe",event ,  Thread.current)
        }.disposed(by: rx.disposeBag)
    }
    
    // 该方法创建一个永远不会发出 Event（也不会终止）的 Observable 序列。
    func observable_never(){
        Observable<Int>.never().subscribe { event in
            print("observable_never subscribe",event ,  Thread.current)
        }.disposed(by: rx.disposeBag)
    }
    
    // 该方法创建一个不做任何操作，而是直接发送一个错误的 Observable 序列。
    func observable_error(){
        enum MyError : Int, Error{
            case one
        }
        Observable<Int>.error(MyError.one).subscribe { event in
            print("observable_error subscribe",event ,  Thread.current)
        }.disposed(by: rx.disposeBag)
    }
    
    // 该方法创建一个不做任何操作，而是直接发送一个错误的 Observable 序列。
    func observable_range(){
        Observable.range(start: 1, count: 5).subscribe { event in
            print("observable_range subscribe",event ,  Thread.current)
        }.disposed(by: rx.disposeBag)
    }
    
    
    // 创建一个可以无限发出给定元素的 Event的 Observable 序列（永不终止）
    func observable_repeatElement(){
        Observable.repeatElement(1).subscribe { event in
            print("observable_repeatElement subscribe",event ,  Thread.current)
        }.disposed(by: rx.disposeBag)
    }
    
    
    // 创建一个只有当提供的所有的判断条件都为 true 的时候，才会给出动作的 Observable 序列
    func observable_generate(){
        Observable.generate(initialState: 0,
                            condition: { $0 <= 10 },
                            iterate: { $0 + 2 }).subscribe { event in
            print("observable_generate subscribe",event ,  Thread.current)
        }.disposed(by: rx.disposeBag)
    }
    
    // 创建一个 Observable 工厂，通过传入一个 block 来执行延迟 Observable序列创建的行为，而这个 block 里就是真正的实例化序列对象的地方
    func observable_deferred(){
        var isOld = false
        let isOldObservable = Observable<Int>.deferred {
            isOld = !isOld
            return isOld ? Observable.of(1, 3, 5 ,7) : Observable.of(2, 4, 6 ,8)
        }
        
        isOldObservable.subscribe { event in
            print("observable_deferred subscribe 1",event ,  Thread.current)
        }.disposed(by: rx.disposeBag)
        
        
        isOldObservable.subscribe { event in
            print("observable_deferred subscribe 2",event ,  Thread.current)
        }.disposed(by: rx.disposeBag)
    }
    
    
    // 创建的 Observable 序列每隔一段设定的时间，会发出一个索引数的元素。而且它会一直发送下去
    func observable_interval(){
        Observable<Int>.interval(.seconds(1), scheduler: MainScheduler.instance).subscribe(onNext: { Int in
            print("observable_interval onNext ",Int ,  Thread.current)
        },onDisposed: {
            print("observable_interval onDisposed ", Thread.current)
        }).disposed(by: rx.disposeBag)
    }
    
    // 创建的 Observable 序列每隔一段设定的时间，会发出一个索引数的元素。而且它会一直发送下去
    func observable_timer(){
        Observable<Int>.timer(.seconds(3) , period: .seconds(2), scheduler: MainScheduler.instance).subscribe { event in
            print("observable_timer subscribe ",event ,  Thread.current)
        }.disposed(by: rx.disposeBag)
        
        // 使用和实现的情景
        // 开发一个倒计时，每一秒改变一个值，点击开始时延时 5秒开始计时
        // 给一个准备的时间
        
    }
    
    // 创建的 Observable 序列每隔一段设定的时间，会发出一个索引数的元素。而且它会一直发送下去
    func observable_do(){
        Observable<Int>.of(1 , 2 ).do(onNext: { value in
            print("observable_do do onNext ", value ,  Thread.current)
        }, afterNext: { value in
            print("observable_do do afterNext ", value ,  Thread.current)
        }, onError: { error in
            print("observable_do do onError ", error ,  Thread.current)
        }, afterError: { error in
            print("observable_do do afterError ", error ,  Thread.current)
        }, onCompleted: {
            print("observable_do do onCompleted ", Thread.current)
        }, afterCompleted: {
            print("observable_do do afterCompleted ", Thread.current)
        }, onSubscribe: {
            print("observable_do do onSubscribe ", Thread.current)
        }, onSubscribed: {
            print("observable_do do onSubscribed ", Thread.current)
        }, onDispose: {
            print("observable_do do onDispose ", Thread.current)
        }).subscribe { value in
            print("observable_do subscribe onNext ", value, Thread.current)
        } onError: { error in
            print("observable_do subscribe onError ", Thread.current)
        } onCompleted: {
            print("observable_do subscribe onCompleted ", Thread.current)
        } onDisposed: {
            print("observable_do subscribe onDisposed ", Thread.current)
        }.disposed(by: rx.disposeBag)
        
    }
    
    /**
     【observeOn，subscribeOn】
     CurrentThreadScheduler 表示当前线程 Scheduler。（默认使用这个）
     MainScheduler：表示主线程
     SerialDispatchQueueScheduler：封装了 GCD 的串行队列。
     ConcurrentDispatchQueueScheduler：封装了 GCD 的并行队列。
     OperationQueueScheduler：封装了 NSOperationQueue
     */
    func observable_observe_subscribe(){
        Observable.create({ simmit in
            print("create", Thread.current)
            Thread.sleep(forTimeInterval: 1000.0)
            simmit.onNext("String1 \(Date.init().timeIntervalSince1970)")
            Thread.sleep(forTimeInterval: 1000.0)
            simmit.onNext("String2  \(Date.init().timeIntervalSince1970)")
            Thread.sleep(forTimeInterval: 1000.0)
            simmit.onNext("String3  \(Date.init().timeIntervalSince1970)")
            Thread.sleep(forTimeInterval: 1000.0)
            simmit.onCompleted()
            
            return Disposables.create()
            
        }).observe(on: MainScheduler.instance)
            .subscribe(on: ConcurrentDispatchQueueScheduler.init(qos: .userInitiated))
            .bind { text in
                print("bind",text ,  Thread.current)
            }.disposed(by: rx.disposeBag)
    }
    
    
    func use_AnyObserverAndBinder (){
        // 实现使用这两个的一个场景
        // 一个输入框UIEditView负责写入字符，一个UILabel负责动态展示
        DDLogDebug("use_AnyObserverAndBinder getcurrent =   \(UIViewController.getCurrentViewController())")
        startViewController(AnyObserverAndBinderViewController(viewModel: AnyObserverAndBinderViewModel()))
    }
    
    
    func use_request(){
        let url = URL(string:"https://www.douban.com/j/app/radio/channels")!
        
        request(.get, url)
            .data() // responseString 如果请求的数据是字符串类型的，我们可以在 request 请求时直接通过 responseString()方法实现自动转换，省的在回调中还要手动将 data 转为 string
            .subscribe { request in
                print("use_request onnext" ,request)
            } onError: { error in
                
                print("use_request onError",error)
            } onCompleted: {
                
                print("use_request onCompleted" )
            } onDisposed: {
                
                print("use_request onDisposed")
            }.disposed(by: rx.disposeBag)
        
    }
    
    
    func use_request_data(){
        let url = URL(string:"https://www.douban.com/j/app/radio/channels")!
        
        requestData(.get, url).subscribe { (response, data) in
            print("use_request onnext" ,response.statusCode , String(data: data, encoding: String.Encoding.utf8) )
        } onError: { error in
            
            print("use_request onError" ,error)
        } onCompleted: {
            
            print("use_request onCompleted")
        } onDisposed: {
            
            print("use_request onDisposed")
        }.disposed(by: rx.disposeBag)
    }
    
    /**
     
     */
    func use_request_json(){
        let url = URL(string:"https://www.douban.com/j/app/radio/channels")!
        // json的第1方式
        //        requestData(.get, url).subscribe { (response, data) in
        //            let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
        //                        as! [String: Any]
        //            print("use_request_json onNext \n" ,json)
        //        } onError: { error in
        //
        //            print("use_request_json onError" ,error)
        //        } onCompleted: {
        //
        //            print("use_request_json onCompleted")
        //        } onDisposed: {
        //
        //            print("use_request_json onDisposed")
        //        }.disposed(by: rx.disposeBag)
        
        // json的第二中方式
        //
        //        request(.get, url)
        //            .responseJSON()
        //            .subscribe { (jsonData) in
        //            print("use_request_json responseJSON onNext \n" ,jsonData)
        //        } onError: { error in
        //            print("use_request_json responseJSON onError" ,error)
        //        } onCompleted: {
        //            print("use_request_json responseJSON onCompleted")
        //        } onDisposed: {
        //            print("use_request_json responseJSON onDisposed")
        //        }.disposed(by: rx.disposeBag)
        //
        
        // json的第3方式
        requestJSON(.get, url)
            .subscribe { (resopnse , jsonData) in
                print("use_request_json requestJSON onNext \n" ,jsonData)
            } onError: { error in
                print("use_request_json requestJSON onError" ,error)
            } onCompleted: {
                print("use_request_json requestJSON onCompleted")
            } onDisposed: {
                print("use_request_json requestJSON onDisposed")
            }.disposed(by: rx.disposeBag)
        
    }
    
    /**
     
     */
    func use_request_json_to_bean(){
        let url = URL(string:"https://www.douban.com/j/app/radio/channels")!
        // json的第1方式 ObjectMapper
        //        requestData(.get, url).subscribe { (response, data) in
        //            // 直接转为json对象
        //            guard let json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
        //                    as? [String: Any] else {
        //                return ;
        //            }
        //            print("use_request_json_to_bean onNext 1 \n" ,type(of: json),json)
        //            //Object Mapper
        //            let object = Mapper<Douban.Object>().map(JSON: json)
        //
        //            print("use_request_json_to_bean onNext 2 \n" ,type(of: object),object ,object?.channels?.count)
        //        } onError: { error in
        //
        //            print("use_request_json_to_bean onError" ,error)
        //        } onCompleted: {
        //
        //            print("use_request_json_to_bean onCompleted")
        //        } onDisposed: {
        //
        //            print("use_request_json_to_bean onDisposed")
        //        }.disposed(by: rx.disposeBag)
        
        // json的第2方式 SwiftyJSON
        requestData(.get, url).subscribe { (response, data) in
            // 直接转为json对象
            guard let jsonObj = try? JSON.init(data: data) else {
                return
            }
            print("use_request_json_to_bean onNext 1 \n" ,type(of: jsonObj))
            print("use_request_json_to_bean onNext 2 \n" ,jsonObj)
            print("use_request_json_to_bean onNext 3 \n" ,jsonObj["channels"])
            print("use_request_json_to_bean onNext 4 \n" ,jsonObj["channels"].array?.count)
            
        } onError: { error in
            
            print("use_request_json_to_bean onError" ,error)
        } onCompleted: {
            
            print("use_request_json_to_bean onCompleted")
        } onDisposed: {
            
            print("use_request_json_to_bean onDisposed")
        }.disposed(by: rx.disposeBag)
        
    }
    
    func use_moya_request(){
        var myProvider = MoyaProvider<DoubanAPI>(plugins: [MoyaLoggingPlugin()])
        myProvider.rx.request(.channels)
            .subscribe { response in
                guard let jsonObj = try? JSON.init(data: response.data) else {
                    return
                }
                print("use_moya_request onNext 1 \n" ,type(of: jsonObj))
                print("use_moya_request onNext 2 \n" ,jsonObj)
                print("use_moya_request onNext 3 \n" ,jsonObj["channels"])
                print("use_moya_request onNext 4 \n" ,jsonObj["channels"].array?.count)
                
            } onFailure: { error in
                print("use_moya_request onFailure 5 \n" ,error)
            } onDisposed: {
                
                print("use_moya_request onDisposed 6 \n" )
            }.disposed(by: rx.disposeBag)
        
    }
    
    
    func use_moya_request_json(){
        var myProvider = MoyaProvider<DoubanAPI>(plugins: [MoyaLoggingPlugin()])
        myProvider.rx.request(.channels)
            .mapJSON()
            .subscribe { data in
                print("use_moya_request_json onNext 1 \n" ,type(of: data))
                print("use_moya_request_json onNext 2 \n" ,data)
            } onFailure: { error in
                print("use_moya_request_json onFailure 2 \n" ,error)
            } onDisposed: {
                print("use_moya_request_json onDisposed 3 \n" )
            }.disposed(by: rx.disposeBag)
    }
    
    func use_moya_request_demo(title:String, message:String){
        //显示消息
        let alertController = UIAlertController(title: title,
                                                message: message, preferredStyle: .alert)
        let cancelAction = UIAlertAction(title: "跳转", style: .cancel, handler: { [weak self]action in
            print(action , "确定")
            self?.startViewController(RxMoyaViewController(viewModel: RxMoyaViewModel.shared))
        })
        alertController.addAction(cancelAction)
        self.present(alertController, animated: true, completion: nil)
    }
}

struct MySection {
    var header: String
    var items: [Item]
}
extension MySection : AnimatableSectionModelType {
    typealias Item = String
    
    var identity: String {
        return header
    }
    
    init(original: MySection, items: [Item]) {
        self = original
        self.items = items
    }
}
